package net.kem.android.positioner;

import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.kem.android.positioner.responsehandler.AddDeleteUpdatePOIResponseHandler;
import net.kem.android.positioner.responsehandler.CurrentLocationResponseHandler;
import net.kem.android.positioner.responsehandler.GetAllObjectsResponseHandler;
import net.kem.android.positioner.responsehandler.GetAllPOIsResponseHandler;
import net.kem.android.positioner.responsehandler.ResponseHandler;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.util.Xml;

public class PositionerService extends Service {
	public static final String EXTRA_LOCATION = "Extra_Location";
	public static final String EXTRA_LOCATION_ID = "Extra_Location_ID";
	public static final String EXTRA_SCHEDULLED_CALL = "Extra_Schedulled_Call";

	private NotificationState currentNotificationState;
	private LocationManager locationManager;
	private LocationListener locationListener;
	private AlarmManager alarmManager;
	private PendingIntent alarmPI;
	private IBinder binder;
	private Bundle currentGPSSettings;
	private BackgroundSender backgroundSender;
//	private ServerAlertsHandler serverAlertsHandler;
	private static NotificationManager notificationManager;

	private static enum NotificationMode {NET_OFF, NET_ON, GPS_OFF, GPS_ON};
	private static enum NotificationState {
		NONET_NOGPS(R.drawable.notif_nonet_nogps_24x24, R.string.notification_nonet_nogps),
		NONET_GPS(R.drawable.notif_nonet_gps_24x24, R.string.notification_nonet_gps),
		NET_NOGPS(R.drawable.notif_net_nogps_24x24, R.string.notification_net_nogps),
		NET_GPS(R.drawable.notif_net_gps_24x24, R.string.notification_net_gps);

		private int iconId;
		private int titleId;
		private NotificationState(int iconId, int titleId) {
			this.iconId = iconId;
			this.titleId = titleId;
		}
		static NotificationState changeNotificationState(NotificationMode mode, NotificationState currentNotificationState, Context context, Notification notification, PendingIntent contentIntent) {
			NotificationState newNotificationState = currentNotificationState;
			switch(mode) {
			case GPS_OFF:
				if(currentNotificationState == NONET_GPS) {
					newNotificationState = NONET_NOGPS;
					break;
				}
				if(currentNotificationState == NET_GPS) {
					newNotificationState = NET_NOGPS;
					break;
				}
				break;
			case GPS_ON:
				if(currentNotificationState == NET_NOGPS) {
					newNotificationState = NET_GPS;
					break;
				}
				if(currentNotificationState == NONET_NOGPS) {
					newNotificationState = NONET_GPS;
					break;
				}
				break;
			case NET_OFF:
				if(currentNotificationState == NET_GPS) {
					newNotificationState = NONET_GPS;
					break;
				}
				if(currentNotificationState == NET_GPS) {
					newNotificationState = NONET_GPS;
					break;
				}
				break;
			case NET_ON:
				if(currentNotificationState == NONET_NOGPS) {
					newNotificationState = NET_NOGPS;
					break;
				}
				if(currentNotificationState == NONET_GPS) {
					newNotificationState = NET_GPS;
					break;
				}
				break;
			default:
				break;
			}
			if(newNotificationState != currentNotificationState) {
				// Step 4:  Preparing the Notification Event
				String contentTitle = context.getText(R.string.notification_title).toString();
				String contentText = context.getText(newNotificationState.titleId).toString();
				notification.tickerText = context.getText(newNotificationState.titleId);
				notification.icon = newNotificationState.iconId;
				notification.when = System.currentTimeMillis();
				notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
				// Step 5:  Notifying the User
				notificationManager.notify(LIST_UPDATE_NOTIFICATION, notification);
			}
			return newNotificationState;
		}
	};

	private static final int LIST_UPDATE_NOTIFICATION = 100;
	private static final String TEMPLATE_REQUEST_CURRENT_LOCATION =
			"<message sal=\"%d\">" +
			"<idRequest>1</idRequest>" +
			"<phoneNumber>%s</phoneNumber>" +
			"<idFavorite>0</idFavorite>" +
			"<name>%s</name>" +
			"<lat>%1.6f</lat><long>%1.6f</long>" +
			"</message>\r\n";//s s f f

	private static final String TEMPLATE_REQUEST_GET_ALL_POIS =
			"<message sal=\"%d\">" +
				"<idRequest>3</idRequest>" +
				"<phoneNumber>%s</phoneNumber>" +
			"</message>\r\n";//s

	private static final String TEMPLATE_REQUEST_GET_ALL_OBJECTS =
			"<message sal=\"%d\">" +
				"<idRequest>6</idRequest>" +
				"<idObjectType>%d</idObjectType>" +
				"<phoneNumber>%s</phoneNumber>" +
			"</message>\r\n";//s

	private static final String TEMPLATE_REQUEST_SET_OBJECTS =
			"<message sal=\"%d\">" +
				"<idRequest>8</idRequest>" +
				"<phoneNumber>%s</phoneNumber>" +
				"<objects>%s</objects>" +
			"</message>\r\n";//s

	private static final String TEMPLATE_OBJECT =
			"<message sal=\"%d\">" +
				"<idObject>%d</idObject>" +
				"<idObjectType>%d</idObjectType>" +
				"<name>%s</name>" +
				"<state>%s</state>" +
			"</object>";//s

	private static final String TEMPLATE_REQUEST_ADD_POI =
			"<message sal=\"%d\">" +
					"<idRequest>%d</idRequest>" +
					"<phoneNumber>%s</phoneNumber>" +
					"<idType>%d</idType>" +
					"<name>%s</name>" +
					"<lat>%1.6f</lat><long>%1.6f</long>" +
					"</message>\r\n";

	private static final String TEMPLATE_REQUEST_UPDATE_POI =
			"<message sal=\"%d\">" +
					"<idRequest>%d</idRequest>" +
					"<phoneNumber>%s</phoneNumber>" +
					"<idFavorite>%d</idFavorite>" +
					"<idType>%d</idType>" +
					"<name>%s</name>" +
					"<lat>%1.6f</lat><long>%1.6f</long>" +
					"</message>\r\n";
	private static final String TEMPLATE_REQUEST_DELETE_POI =
			"<message sal=\"%d\">" +
					"<idRequest>5</idRequest>" +
					"<phoneNumber>%s</phoneNumber>" +
					"<idFavorite>%d</idFavorite>" +
					"</message>\r\n";

	@Override
	public void onCreate() {
		Settings.init(this); // Initialize Setting instance.

		// Taken from http://mobile.tutsplus.com/tutorials/android/android-fundamentals-status-bar-notifications/
		// Step 1:  Android Notifications
		final Context context = getApplicationContext();
		notificationManager = (NotificationManager)context.getSystemService(NOTIFICATION_SERVICE);
		currentNotificationState = NotificationState.NONET_NOGPS;
		// Step 3:  Creating a PendingIntent
		Intent notificationIntent = new Intent(context, PositionerActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
		final PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
		// Step 2:  Creating a Notification
		final Notification notification = new Notification();
		notification.flags |= Notification.FLAG_NO_CLEAR;

		currentGPSSettings = new Bundle(4);
		binder = new LocalBinder();
		// Work with GPS service
		locationListener = new LocationListener() {
			@Override
			public void onStatusChanged(String provider, int status, Bundle extras) {
				String sStatus;
				switch(status) {
					case LocationProvider.AVAILABLE: sStatus = "Available";
						currentNotificationState = NotificationState.changeNotificationState(NotificationMode.GPS_ON, currentNotificationState, context, notification, contentIntent);
					break;
					case LocationProvider.OUT_OF_SERVICE: sStatus = "Out-of-service";
						currentNotificationState = NotificationState.changeNotificationState(NotificationMode.GPS_OFF, currentNotificationState, context, notification, contentIntent);
					break;
					case LocationProvider.TEMPORARILY_UNAVAILABLE: sStatus = "Temporarily unavailable";
						currentNotificationState = NotificationState.changeNotificationState(NotificationMode.GPS_OFF, currentNotificationState, context, notification, contentIntent);
					break;
					default: sStatus = "Unknown: " + status;
				}
				Log.i("PS GPS status", "Status of provider " + provider + " has changed to " + sStatus);
			}

			@Override
			public void onProviderEnabled(String provider) {
				currentNotificationState = NotificationState.changeNotificationState(NotificationMode.GPS_ON, currentNotificationState, context, notification, contentIntent);
				Log.i("PS GPS status", "Provider " + provider + " enabled");
			}

			@Override
			public void onProviderDisabled(String provider) {
				currentNotificationState = NotificationState.changeNotificationState(NotificationMode.GPS_OFF, currentNotificationState, context, notification, contentIntent);
				Log.i("PS GPS status", "Provider " + provider + " disabled");
			}

			@Override
			public void onLocationChanged(Location location) {
				sendCurrentLocation(location, 0);
			}
		};

		float gpsRefreshDistance = Settings.getGPSRefreshDistance();
		int gpsRefreshInterval = Settings.getGPSRefreshInterval();
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		addLocationListener(locationListener, gpsRefreshDistance, gpsRefreshInterval);
		// LocationManager.NETWORK_PROVIDER // Can also be used.

		setAuthentication();
/*
		try {
			serverAlertsHandler = new ServerAlertsHandler();
			serverAlertsHandler.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
*/
		backgroundSender = new BackgroundSender(context, notification, contentIntent);
		backgroundSender.start();

		backgroundSender.sendGetAllPOIs();
		//backgroundSender.sendGetAllObjects(int objectsType);//TODO what type should I bring?
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if(intent != null && intent.getExtras() != null) {
			Location location = (Location) intent.getExtras().get(EXTRA_LOCATION);
			int locationId = intent.getIntExtra(EXTRA_LOCATION_ID, 0);
			sendCurrentLocation(location, locationId);
		}
		// If we get killed, after returning from here, restart
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
		/*if(serverAlertsHandler != null) {
			serverAlertsHandler.close();
			serverAlertsHandler = null;
		}*/
		if(alarmManager != null && alarmPI != null) {
			alarmManager.cancel(alarmPI);
		}
		removeLocationListener(locationListener);

		Context context = getApplicationContext();
		NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
		notificationManager.cancel(LIST_UPDATE_NOTIFICATION);

		logAndshowToast(null, "onDestroy", "service done");// Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
	}

	void addLocationListener(LocationListener locationListener, float gpsRefreshDistance, int gpsRefreshInterval) {
		long gpsRefreshIntervalMs;
		if(gpsRefreshInterval == 0) {
			gpsRefreshIntervalMs = 30000L;//30 seconds
		} else {
			gpsRefreshIntervalMs = gpsRefreshInterval * 1000L;
		}
		// GPS service will notify me about new location NO OFTEN THAN every gpsRefreshInterval seconds AND if I move more than gpsRefreshDistance meters.
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, gpsRefreshIntervalMs, gpsRefreshDistance, locationListener);
		Log.d(PositionerService.class.getSimpleName(), "Add Location Listener: " + gpsRefreshIntervalMs + " sec, " + gpsRefreshDistance + " m, " + locationListener.toString());
	}

	void removeLocationListener(LocationListener locationListener) {
		locationManager.removeUpdates(locationListener);
		Log.d(PositionerService.class.getSimpleName(), "Remove Location Listener " + locationListener.toString());
	}

	/**
	 * The IntentService calls this method from the default worker thread with
	 * the intent that started the service. When this method returns,
	 * IntentService stops the service, as appropriate.
	 */
	private void sendCurrentLocation(double latitude, double longitude, int locationId) {
		Location location = new Location(LOCATION_SERVICE);
		location.setLatitude(latitude);
		location.setLongitude(longitude);
		sendCurrentLocation(location, locationId);
	}

	private void sendCurrentLocation(final Location location, final int locationId) {
		if(location == null/* || (locationId == 0 && isWithinRadius(location, Settings.getPOIRadius()))*/) {
			return;
		}
		float accuracy = location.getAccuracy();
		if(accuracy != 0 && accuracy <= Settings.getGPSAccuracyThreshold()) {
			Log.d("PS GPS Location Changed. Apply to server", "Accuracy " + accuracy);
			backgroundSender.sendCurrentLocation(location);
		} else {
			Log.d("PS GPS Location Changed. Don't apply to server", "Accuracy " + accuracy);
		}
	}

	// ---- Binder BEGIN
	/**
	 * Class used for the client Binder. Because we know this service always
	 * runs in the same process as its clients, we don't need to deal with IPC.
	 */
	public class LocalBinder extends Binder {
		String getArressesByLocation(Location location) {
			return PositionerService.this.getArressesByLocation(location);
		}

		void addLocationListener(LocationListener locationListener, float gpsRefreshDistance, int gpsRefreshInterval) {
			if(locationListener == null) {
				locationListener = PositionerService.this.locationListener;
			}
			PositionerService.this.addLocationListener(locationListener, gpsRefreshDistance, gpsRefreshInterval);
		}

		void removeLocationListener(LocationListener locationListener) {
			PositionerService.this.removeLocationListener(locationListener);
		}

		void sendLocation(double latitude, double longitude, int locationId) {
			PositionerService.this.sendCurrentLocation(latitude, longitude, locationId);
		}

		void sendLocation(Location location, int locationId) {
			PositionerService.this.sendCurrentLocation(location, locationId);
		}

		void sendCurrentLocation(Location location) {
			PositionerService.this.sendCurrentLocation(location, 0);
		}
		void sendAddPOI(POI poi) {
			backgroundSender.sendAddPOI(poi);
		}
		void sendUpdatePOI(POI poi) {
			backgroundSender.sendUpdatePOI(poi);
		}
		void sendDeletePOI(POI poi) {
			backgroundSender.sendDeletePOI(poi);
		}
		void sendGetAllPOIs() {
			backgroundSender.sendGetAllPOIs();
		}
		void sendGetAllObjects(int objectsType) {
			backgroundSender.sendGetAllObjects(objectsType);
		}
		public void sendSetObjects(List<MessageObject> objects) {
			backgroundSender.sendSetObjects(objects);
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}
	// ---- Binder END

	private static void setAuthentication() {
		final String username = Settings.getUsername();
		final String password = Settings.getPassword();
		Authenticator.setDefault(new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password.toCharArray());
			}
		});
	}

	private String getArressesByLocation(Location location) {
		String res = null;
		Geocoder geoCoder = new Geocoder(getBaseContext(), Locale.ENGLISH);// Locale.getDefault()
		try {
			List<Address> addresses = geoCoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
			if (addresses.size() > 0) {
				res = "";
				for (int index = 0; index < addresses.get(0).getMaxAddressLineIndex(); index++)
					res += addresses.get(0).getAddressLine(index) + " ";
			}
		} catch (IOException e) {
			Log.e("convertPointToLocation", "Could not get location address: " + e.getMessage());
		}
		return res;
	}

	private boolean isWithinRadius(Location currentLocation) {
		int radius = Settings.getPOIRadius();
		return isWithinRadius(currentLocation, radius);
	}
	private boolean isWithinRadius(Location currentLocation, int radius) {
		boolean res;
		for(POI poi: Settings.getPOIs()) {
			res = isWithinRadius(currentLocation, poi.getCoordinates(), radius);
			if (res) {
				String poiName = poi.getName();
				Log.d("withinRadius", "Inside " + radius + " meters from " + poiName);
				return true;
			}
		}
		Log.d("withinRadius", "Out of " + radius + " meters from all known POIs");
		return false;
	}
	private boolean isWithinRadius(Location currentLocation, String poiName, int radius) {
		POI poi = Settings.getPOIByName(poiName);
		if (poi != null) {
			if (isWithinRadius(currentLocation, poi.getCoordinates(), radius)) {
				Log.d("withinRadius", "Inside " + radius + " meters from " + poiName);
				return true;
			}
			Log.d("withinRadius", "Out of " + radius + " meters from all known POIs");
		}
		return false;
	}
	private boolean isWithinRadius(Location currentLocation, Location location, int radius) {
		if (location != null) {
			float distance = currentLocation.distanceTo(location);
			if (distance < radius) {
				return true;
			}
		}
		return false;
	}

	enum RequestType {CURRENT_LOCATION, ADD_POI, UPDATE_POI, DELETE_POI, GET_ALL_POIS, GET_ALL_OBJECTS, SET_OBJECTS};
	private class BackgroundSender extends Thread {
		private String host;
		private int port;
		private String username;
		private Location location;
		private RequestType requestType;
		private POI poi;
		private String payload;
		private Context context;
		private Notification notification;
		private PendingIntent contentIntent;
		private Class<? extends Activity> toastTo;
		public BackgroundSender(Context context, Notification notification, PendingIntent contentIntent) {
			this.context = context;
			this.notification = notification;
			this.contentIntent = contentIntent;
		}
		synchronized void sendCurrentLocation(Location location) {
			requestType = RequestType.CURRENT_LOCATION;
			this.location = location;
			username = Settings.getUsername();
			String currentAddress = getArressesByLocation(location);
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_CURRENT_LOCATION, 0, username, currentAddress == null ? "": currentAddress, location.getLatitude(), location.getLongitude());
			toastTo = PositionerActivity.class;
			logAndshowToast(toastTo, "talkToServer","Tx CURRENT@" + location.getLatitude() + "x" + location.getLongitude());
			notifyAll();
		}
		synchronized void sendAddPOI(POI poi) {
			this.poi = poi;
			this.location = poi.getCoordinates();
			requestType = RequestType.ADD_POI;
			username = Settings.getUsername();
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_ADD_POI, 0, 2, username, poi.getType(), poi.getName(), poi.getCoordinates().getLatitude(), poi.getCoordinates().getLongitude());
			toastTo = PreferencesFromXml.class;
			logAndshowToast(toastTo, "talkToServer","Tx AddPOI" + poi.getName());
			notifyAll();
		}
		synchronized void sendUpdatePOI(POI poi) {
			this.poi = poi;
			this.location = poi.getCoordinates();
			requestType = RequestType.UPDATE_POI;
			username = Settings.getUsername();
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_UPDATE_POI, 0, 4, username, poi.getId(), poi.getType(), poi.getName(), poi.getCoordinates().getLatitude(), poi.getCoordinates().getLongitude());
			toastTo = PreferencesFromXml.class;
			logAndshowToast(toastTo, "talkToServer","Tx UpdPOI@" + poi.getName());
			notifyAll();
		}
		synchronized void sendDeletePOI(POI poi) {
			this.poi = poi;
			this.location = poi.getCoordinates();
			requestType = RequestType.DELETE_POI;
			username = Settings.getUsername();
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_DELETE_POI, 0, username, poi.getId());
			toastTo = PreferencesFromXml.class;
			logAndshowToast(toastTo, "talkToServer","Tx DelPOI@" + poi.getName());
			notifyAll();
		}
		synchronized void sendGetAllPOIs() {
			requestType = RequestType.GET_ALL_POIS;
			username = Settings.getUsername();
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_GET_ALL_POIS, 0, username);
			toastTo = PositionerActivity.class;
			logAndshowToast(toastTo, "talkToServer","Tx GetAllPOIs");
			notifyAll();
		}
		synchronized void sendGetAllObjects(int objectsType) {
			requestType = RequestType.GET_ALL_OBJECTS;
			username = Settings.getUsername();
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_GET_ALL_OBJECTS, 0, objectsType, username);
			toastTo = ServerMessagesActivity.class;
			logAndshowToast(toastTo, "talkToServer","Tx GetAllObjects");
			notifyAll();
		}
		synchronized void sendSetObjects(List<MessageObject> objects) {
			requestType = RequestType.SET_OBJECTS;
			username = Settings.getUsername();
			StringBuilder sb = new StringBuilder(128);
			for (MessageObject messageObject: objects) {
				sb.append(messageObject.toXML());
			}
			payload = String.format(Locale.ENGLISH, TEMPLATE_REQUEST_SET_OBJECTS, 0, username, sb.toString());
			toastTo = ServerMessagesActivity.class;
			logAndshowToast(toastTo, "talkToServer","Tx SetAllObjects");
			notifyAll();
		}
		@Override
		public void run() {
			int currentGPSRefreshInterval = Settings.getGPSRefreshInterval();
			int currentGPSRefreshDistance = Settings.getGPSRefreshDistance();
			Looper.myLooper();
			Looper.prepare();
			while(true) {
				try {
					synchronized(this) {
						wait();
					}

					String response = null;
					if(requestType == RequestType.GET_ALL_OBJECTS) {
						Pattern p = Pattern.compile("..*<idObjectType>(-?\\d+)</idObjectType>.*\r\n");
						Matcher m = p.matcher(payload);
						if(m.matches()) {
							int objectsType = Integer.parseInt(m.group(1));
							if(objectsType < 0) {
								String DUMMY_RESPONSE = "<message>"
										+ "\t<phoneNumber>" + username + "</phoneNumber>	<!-- Sender's phone number. For debug purposes only -->"
										+ "\t<status>0</status>         <!-- Integer. 0 if get Objects operation was successful. -->"
										+ "\t<descr>bla.bla</descr>     <!-- Optional string. Contains error description if status != 0 -->"
										+ "\t<objects>"
										+ "\t\t<object>"
										+ "\t\t\t<idObject>1</idObject>"
										+ "\t\t\t<idObjectType>1</idObjectType>"
										+ "\t\t\t<name>Living Room " + System.currentTimeMillis()%1000 + "</name>"
										+ "\t\t\t<state>State is ON</state>"
										+ "\t\t</object>"
										+ "\t\t<object>"
										+ "<idObject>2</idObject>"
										+ "\t\t\t<idObjectType>1</idObjectType>"
										+ "\t\t\t<name>Hall " + System.currentTimeMillis()%1000 + "</name>"
										+ "\t\t\t<state>State is OFF</state>"
										+ "\t\t</object>"
										+ "\t</objects>"
										+ "</message>";
								response = DUMMY_RESPONSE;
							}
						}
					}
					if(response == null) {
						// Use home WiFI if available.
						boolean homeWiFiAvailable = false;
						String homeWiFiId = Settings.getHomeWiFiId();
						if(homeWiFiId != null && homeWiFiId.length() > 0) {
							ConnectivityManager connManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
							NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
							if (mWifi.isConnected()) {
								//if wifi connected
								WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
								WifiInfo wifiInfo = wifi.getConnectionInfo();// SSID: Keshet-Guest, BSSID: c4:7d:4f:52:c7:71, MAC: 00:7d:13:45:2a:f3, Supplicant state: COMPLETED, RSSI: -59, Link speed: -1, Net ID: 2, Explicit connect: false
								String ssid = wifiInfo.getSSID();
								if(ssid != null && ssid.equals(homeWiFiId)) {
									String wiFiHost = Settings.getWiFiHost();
									if(wiFiHost != null && wiFiHost.length() > 0) {
										int wiFiPort = Settings.getWiFiPort();
										host = wiFiHost;
										port = wiFiPort;
										homeWiFiAvailable = true;
									}
								}
							}
							//NetworkInfo mMobile = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
							//if (mMobile.isConnected()) {
							//	//if internet connected
							//}
						}
						if(!homeWiFiAvailable) {
							host = Settings.getHost();
							port = Settings.getPort();
						}

						// Send data to server and get response.
						long start = System.currentTimeMillis();
						response = TalkToServer.talkToServer(host, port, payload, true);
						long delta = System.currentTimeMillis() - start;
						logAndshowToast(toastTo, "talkToServer", String.valueOf(delta));
					}

					currentNotificationState = NotificationState.changeNotificationState(NotificationMode.NET_ON, currentNotificationState, context, notification, contentIntent);

					switch(requestType) {
					case CURRENT_LOCATION:
						//String response = "<message><distance>50</distance><interval>20</interval></message>";//TODO
						CurrentLocationResponseHandler parserCurLoc = new CurrentLocationResponseHandler();
						Xml.parse(response, parserCurLoc);
						if(!username.equals(parserCurLoc.getUserName())) {
							//TODO show error
							break;
						}

						// Check whether location listener parameters should be updated.
						boolean updateLocationListenerSettings = false;
						if(Settings.getGPSAutoRefreshDistance()) {
							// Refresh and Interval are dictated by server. Get'em from response.
							int suggestedGPSRefreshDistance = parserCurLoc.getDistance();
							if(suggestedGPSRefreshDistance > 0) {
								if(currentGPSRefreshDistance != suggestedGPSRefreshDistance) {
									currentGPSRefreshDistance = suggestedGPSRefreshDistance;
									updateLocationListenerSettings = true;
								}
							}
							int suggestedGPSRefreshInterval = parserCurLoc.getInterval();
							if(suggestedGPSRefreshInterval > 0) {
								if(currentGPSRefreshInterval != suggestedGPSRefreshInterval) {
									currentGPSRefreshInterval = suggestedGPSRefreshInterval;
									updateLocationListenerSettings = true;
								}
							}
						}
						if(updateLocationListenerSettings) {
//							removeLocationListener(locationListener);
							addLocationListener(locationListener, currentGPSRefreshDistance, currentGPSRefreshInterval);
							// Check if you're within POI radius.
							currentGPSSettings.putBoolean("inPOIRadius", isWithinRadius(location));
							currentGPSSettings.putInt("currentGPSRefreshDistance", currentGPSRefreshDistance);
							currentGPSSettings.putInt("currentGPSRefreshInterval", currentGPSRefreshInterval);
							currentGPSSettings.putFloat("currentLocationAccuracy", location.getAccuracy());
							informOthers();
						}
						logAndshowToast(toastTo, "talkToServer", "Rx " + parserCurLoc.getDistance() + " X " + parserCurLoc.getInterval());// Toast.makeText(PositionerService.this, "Rx " + response, Toast.LENGTH_SHORT).show();
						break;
					case GET_ALL_POIS:
						GetAllPOIsResponseHandler parserGetAllPOIS = new GetAllPOIsResponseHandler();
						Xml.parse(response, parserGetAllPOIS);
						if(parserGetAllPOIS.getStatus() != ResponseHandler.STATUS_OK) {
							String errMsg = parserGetAllPOIS.getDescription();
							logAndshowToast(toastTo, "talkToServer","ERROR: Could not get all POIs: " + errMsg);
							break;
						}
						if(!username.equals(parserGetAllPOIS.getUserName())) {
							logAndshowToast(toastTo, "talkToServer","ERROR: Misaddressed response");
							break;
						}
						List<POI> pois = parserGetAllPOIS.getPois();
						Settings.storePOIs(pois);
						break;
					case GET_ALL_OBJECTS:
						GetAllObjectsResponseHandler parserGetAllObjects = new GetAllObjectsResponseHandler();
						Xml.parse(response, parserGetAllObjects);
						if(parserGetAllObjects.getStatus() != ResponseHandler.STATUS_OK) {
							String errMsg = parserGetAllObjects.getDescription();
							logAndshowToast(ServerMessagesActivity.class, "talkToServer","ERROR: Could not get all POIs: " + errMsg);
							break;
						}
						if(!username.equals(parserGetAllObjects.getUserName())) {
							logAndshowToast(ServerMessagesActivity.class, "talkToServer","ERROR: Misaddressed response");
							break;
						}
						ArrayList<MessageObject> messageObjects = parserGetAllObjects.getMessageObjects();
						informServerMessages(messageObjects);
						break;
					case SET_OBJECTS:
						//TODO Implement.
						break;
					case ADD_POI:
					case DELETE_POI:
					case UPDATE_POI:
						AddDeleteUpdatePOIResponseHandler parserADUPOI = new AddDeleteUpdatePOIResponseHandler();
						Xml.parse(response, parserADUPOI);
						if(parserADUPOI.getStatus() != ResponseHandler.STATUS_OK) {
							String errMsg = parserADUPOI.getDescription();
							logAndshowToast(toastTo, "talkToServer","ERROR: Could not process POI: " + errMsg);
							break;
						}
						if(!username.equals(parserADUPOI.getUserName())) {
							logAndshowToast(toastTo, "talkToServer","ERROR: Misaddressed response");
							break;
						}
						if(requestType == RequestType.DELETE_POI) {
							POI.delete(poi);
							logAndshowToast(toastTo, "talkToServer","POI " + poi.getName() + " was deleted");
						} else {
							poi.setId(parserADUPOI.getPoiId());
							poi.store();
							logAndshowToast(toastTo, "talkToServer","POI " + poi.getName() + " was saved");
						}
						break;
					}
				}
				catch (UnknownHostException e) {
					currentNotificationState = NotificationState.changeNotificationState(NotificationMode.NET_OFF, currentNotificationState, context, notification, contentIntent);
					logAndshowToast(toastTo, "talkToServer", "Send ERR: Unknown host " + host);// Toast.makeText(PositionerService.this, "Send ERR: Unknown host " + host, Toast.LENGTH_SHORT).show();
				} catch (IOException e) {
					currentNotificationState = NotificationState.changeNotificationState(NotificationMode.NET_OFF, currentNotificationState, context, notification, contentIntent);
					logAndshowToast(toastTo, "talkToServer", "Send ERR: " + e.getMessage());// Toast.makeText(PositionerService.this, "Send ERR: " + e.getMessage(), Toast.LENGTH_SHORT).show();
				} catch (InterruptedException e) {
					logAndshowToast(toastTo, "talkToServer", "Interrupted. Quiting");
					break;
				} catch (Exception e) {
					logAndshowToast(toastTo, "talkToServer", "Send Global ERR: " + e.getMessage());// Toast.makeText(PositionerService.this, "Send ERR: " + e.getMessage(), Toast.LENGTH_SHORT).show();
				}
			}
		}
	};
/*
	class ServerAlertsHandler extends Thread {
		private ServerSocket serverAlertsListener;
		ServerAlertsHandler() throws IOException {
			serverAlertsListener = new ServerSocket(0, 3, TalkToServer.getLocalIpAddress(false));
		}
		@Override
		public void run() {
			Socket s = null;
	    	try {
				s = serverAlertsListener.accept();
				String response = TalkToServer.talkToServer(s, null, true);
				ServerAlertResponseHandler parserSrvAlert = new ServerAlertResponseHandler();
				Xml.parse(response, parserSrvAlert);
				if(Settings.getUsername().equals(parserSrvAlert.getUserName())) {
					logAndshowToast(null, "ServerAlert", parserSrvAlert.toString());
				} else {
					//TODO show error
				}
				s.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				if(s != null) {
					try {
						s.close();
					} catch (IOException e) {
						// Ignore
					}
				}
			}
		}
		int getLocalPort() {
			return serverAlertsListener==null? 0: serverAlertsListener.getLocalPort();
		}
		void close() {
			if(serverAlertsListener != null) {
				try {
					serverAlertsListener.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
*/
	protected void logAndshowToast(Class<? extends Activity> to, String tag, String message) {
		Log.d(tag, message);
		Intent intent = new Intent("toastEvent");
		// You can also include some extra data.
		intent.putExtra("to", to==null? "": to.getName());
		intent.putExtra("message", message);
		LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
		//Map<String, String> getCurrentGPSSettings(Map<String, String> currentGPSSettings)
	}
	protected void informOthers() {
		Intent intent = new Intent("custom-event-name");
		// You can also include some extra data.
		intent.putExtra("messageBundle", currentGPSSettings);
		LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
		//Map<String, String> getCurrentGPSSettings(Map<String, String> currentGPSSettings)
	}
	protected void informServerMessages(ArrayList<MessageObject> messageObjects) {
		Bundle bundleMessageObjects = new Bundle();
		bundleMessageObjects.putParcelableArrayList("ServerMessageObjects", messageObjects);
		Intent intent = new Intent("serverMessageEvent");
		// You can also include some extra data.
		intent.putExtra("serverMessage", bundleMessageObjects);
		LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
		//Map<String, String> getCurrentGPSSettings(Map<String, String> currentGPSSettings)
	}
}